﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using visinia.SmartEngine.Cache;
using visinia.SmartEngine.Providers;

namespace visinia.SmartEngine.Modules
{
    /// <summary>
    /// The module controller class used to add delete update the module
    /// to the data store, also used to add delete update the
    /// module specific data aka module private settings.
    /// </summary>
    public class ModuleController
    {
        #region CACHE KEYS
        private const string KEY_MODULES = "ModulesForPage_{0}";
        private const int MODULES_EXPIRY = 20;
        private const string KEY_MODULE = "Module_{0}";
        private const int MODULE_EXPIRY = 20;
        private const string KEY_MODULE_SETTINGS = "ModuleSettings_{0}";
        #endregion

        /// <summary>
        /// Fired when a module is deleted
        /// </summary>
        public static event EventHandler<EventArgs> ModuleDeleted;
        public static void OnModuleDeleted(object sender, EventArgs arg)
        {
            if (ModuleDeleted != null)
            {
                ModuleDeleted(sender, arg);
            }
        }

        /// <summary>
        /// Adds a new module
        /// </summary>
        /// <param name="module">The module to add</param>
        /// <returns>The id of the newly added module</returns>
        public static int AddModule(ModuleInfo module)
        {
            if (module == null)
                return 0;
            IDataReader dr = SmartEngineDataProvider.Provider.AddModule(module.ModuleInstalledId, module.Title, module.TitleImageUrl, module.TitleImageNavigationUrl, module.CssClass, module.Width, module.Height, module.PageId, module.Pane, module.PaneOrder, module.Visible);
            int index = 0;
            while (dr.Read())
            {
                if (dr[0] != Convert.DBNull)
                    index = (int)dr[0];
            }
            DataCache.DeleteCacheMultiple("Module");
            dr.Close();
            //LogController.AddLog("New Module Added");
            return index;
        }

        /// <summary>
        /// Deletes the specified module and its private settings
        /// </summary>
        /// <param name="ModuleId">The id of the module to delete</param>
        public static void DeleteModule(int ModuleId)
        {
            SmartEngineDataProvider.Provider.DeleteModule(ModuleId);
            DataCache.DeleteCacheMultiple("Module");
            OnModuleDeleted(ModuleId, new EventArgs());
        }

        /// <summary>
        /// Updated the specified module
        /// </summary>
        /// <param name="module">The module to update</param>
        public static void UpdateModule(ModuleInfo module)
        {
            if (module == null)
                return;
            SmartEngineDataProvider.Provider.UpdateModule(module.ModuleId, module.ModuleInstalledId, module.Title, module.TitleImageUrl, module.TitleImageNavigationUrl, module.CssClass, module.Width, module.Height, module.PageId, module.Pane, module.PaneOrder, module.Visible);
            DataCache.DeleteCacheMultiple("Module");
        }

        /// <summary>
        /// Gets the specified module
        /// </summary>
        /// <param name="ModuleId">The id of the module to return</param>
        public static ModuleInfo GetModule(int ModuleId)
        {
            string key = string.Format(KEY_MODULE, ModuleId);
            ModuleInfo module = (ModuleInfo)DataCache.GetCache(key);
            if (module == null)
            {
                module = FillModule(SmartEngineDataProvider.Provider.GetModule(ModuleId));
                DataCache.SetCache(key, module, new TimeSpan(0, MODULE_EXPIRY, 0));
            }
            return module;
        }

        internal static List<ModuleInfo> GetModules(List<int> ModuleIds)
        {
            List<ModuleInfo> modules = new List<ModuleInfo>();
            foreach (int ModuleId in ModuleIds)
            {                
                modules.Add(GetModule(ModuleId));
            }
            return modules;
        }

        /// <summary>
        /// Gets the specified page modules
        /// </summary>
        /// <param name="PageId">The page id whose modules to return</param>
        public static List<ModuleInfo> GetModules(int PageId)
        {
            return GetModules(GetModuleIdsByPage(PageId));            
        }

        private static List<int> GetModuleIdsByPage(int PageId)
        {
            string key = string.Format(KEY_MODULES, PageId);
            List<int> modulesIds = (List<int>)DataCache.GetCache(key);
            if (modulesIds == null)
            {
                modulesIds = new List<int>();
                IDataReader dr = SmartEngineDataProvider.Provider.GetModules(PageId);
                while (dr.Read())
                {
                    if (dr["ModuleId"] != Convert.DBNull)
                        modulesIds.Add((int)dr["ModuleId"]);
                }
                dr.Close();
                DataCache.SetCache(key, modulesIds, new TimeSpan(0, 20, 0));
            }
            return modulesIds;
        }

        /// <summary>
        /// Gets all the module of the specified page's specified pane
        /// </summary>
        /// <param name="PageId">The page id whose pane's modules to return</param>
        /// <param name="Pane">The pane whose modules to return</param>
        public static List<ModuleInfo> GetModules(int PageId, string Pane)
        {
            return GetModules(GetModuleIdsByPage(PageId)).FindAll(p => (string.Compare(p.Pane, Pane, true) == 0));            
        }

        #region PRIVATE METHODS
        private static ModuleInfo FillModule(IDataReader dr)
        {
            if (dr.Read())
            {
                return ActualRead(dr, true);
            }
            return null;
        }        
        private static ModuleInfo ActualRead(IDataReader dr, bool CloseDataReader)
        {
            ModuleInfo module = new ModuleInfo();
            if (dr["ModuleId"] != Convert.DBNull)
                module.ModuleId = (int)dr["ModuleId"];
            if (dr["ModuleInstalledId"] != Convert.DBNull)
                module.ModuleInstalledId = (int)dr["ModuleInstalledId"];
            if (dr["PageId"] != Convert.DBNull)
                module.PageId = (int)dr["PageId"];

            if (dr["ModuleUrl"] != Convert.DBNull)
                module.ModuleUrl = (string)dr["ModuleUrl"];
            if (dr["ModuleSettingsUrl"] != Convert.DBNull)
                module.ModuleSettingsUrl = (string)dr["ModuleSettingsUrl"];

            if (dr["Title"] != Convert.DBNull)
                module.Title = (string)dr["Title"];

            if (dr["TitleImageUrl"] != Convert.DBNull)
                module.TitleImageUrl = (string)dr["TitleImageUrl"];
            if (dr["TitleImageNavigationUrl"] != Convert.DBNull)
                module.TitleImageNavigationUrl = (string)dr["TitleImageNavigationUrl"];
            
            if (dr["Width"] != Convert.DBNull)
                module.Width = (int)dr["Width"];
            if (dr["Height"] != Convert.DBNull)
                module.Height = (int)dr["Height"];
            if (dr["CssClass"] != Convert.DBNull)
                module.CssClass = (string)dr["CssClass"];
            if (dr["Pane"] != Convert.DBNull)
                module.Pane = (string)dr["Pane"];
            if (dr["PaneOrder"] != Convert.DBNull)
                module.PaneOrder = (int)dr["PaneOrder"];
            if (dr["Visible"] != Convert.DBNull)
                module.Visible = (bool)dr["Visible"];
            if(CloseDataReader)
                dr.Close();
            return module;
        }
        #endregion

        #region ModulePrivateSettings        
        /// <summary>
        /// Returns the specified module's private settings
        /// </summary>
        /// <param name="ModuleId">The id of the module whose private data to return</param>
        /// <returns>The module private settings</returns>
        public static Hashtable GetModulePrivateSettings(int ModuleId)
        {
            string key = string.Format(KEY_MODULE_SETTINGS, ModuleId);
            Hashtable Settings = (Hashtable)DataCache.GetCache(key);            
            if (Settings == null)
            {
                Settings = new Hashtable();
                IDataReader dr = SmartEngineDataProvider.Provider.GetModulePrivateSettings(ModuleId);
                while (dr.Read())
                {
                    if (!dr.IsDBNull(1))
                    {
                        Settings[dr.GetString(0)] = dr.GetString(1);
                    }
                    else
                        Settings[dr.GetString(0)] = "";
                }
                dr.Close();
                DataCache.SetCache(key, Settings);
            }
            return Settings;
        }

        /// <summary>
        /// Adds a new module private setting
        /// </summary>
        /// <param name="ModuleId">The module whose setting to add</param>
        /// <param name="key">The name of the setting</param>
        /// <param name="value">The value of the setting</param>
        public static void AddModulePrivateSetting(int ModuleId, string key, string value)
        {
            SmartEngineDataProvider.Provider.AddModulePrivateSetting(ModuleId, key, value);
            DataCache.DeleteCacheMultiple("ModuleSettings");
        }

        /// <summary>
        /// Updates the specified module private setting
        /// </summary>
        /// <param name="ModuleId">The module whose setting to update</param>
        /// <param name="key">The name of the setting to update</param>
        /// <param name="value">The new value of the spcified setting</param>
        public static void UpdateModulePrivateSetting(int ModuleId, string key, string value)
        {
            SmartEngineDataProvider.Provider.UpdateModulePrivateSetting(ModuleId, key, value);
            DataCache.DeleteCacheMultiple("ModuleSettings");
        }

        /// <summary>
        /// Deletes all specified module private settings
        /// </summary>
        /// <param name="ModuleId">The id of the module whose all private settings to remove</param>
        public static void DeleteModulePrivateSettings(int ModuleId)
        {
            SmartEngineDataProvider.Provider.DeleteModulePrivateSettings(ModuleId);
            DataCache.DeleteCacheMultiple("ModuleSettings");
        }

        /// <summary>
        /// Deletes the specified module's specified setting
        /// </summary>
        /// <param name="ModuleId">The module id whose setting to delete</param>
        /// <param name="key">The name of the setting which to remove</param>
        public static void DeleteModulePrivateSetting(int ModuleId, string key)
        {
            SmartEngineDataProvider.Provider.DeleteModulePrivateSetting(ModuleId, key);
            DataCache.DeleteCacheMultiple("ModuleSettings");
        }
        #endregion
    }
}
